﻿using System;
using UIKit;
using Foundation;
using CoreAnimation;
using CoreGraphics;
using ObjCRuntime;


namespace Akari.XaTouch.MMMaterialDesignSpinner
{
	public class MaterialDesignSpinner : UIView
	{
		#region Event

		#endregion

		#region Field

		private static NSString kMMRingStrokeAnimationKey = new NSString(@"mmmaterialdesignspinner.stroke");
		private static NSString kMMRingRotationAnimationKey = new NSString(@"mmmaterialdesignspinner.rotation");

		private CAShapeLayer _progressLayer;


		#endregion

		#region Property

		public nfloat LineWidth
		{
			get { return _progressLayer.LineWidth; }
			set { _progressLayer.LineWidth = value; }
		}

		public bool HidesWhenStopped { get; set; }

		public CAMediaTimingFunction TimingFunction { get; private set; }

		public bool IsAnimating { get; private set; }

		#endregion

		#region Constructor

		public MaterialDesignSpinner(CGRect frame)
			: base(frame)
		{
			Initilize();
		}

		~MaterialDesignSpinner()
		{
			NSNotificationCenter.DefaultCenter.RemoveObserver(this, UIApplication.DidBecomeActiveNotification);
		}

		#endregion

		#region Method

		public void StartAnimating()
		{
			if (IsAnimating)
				return;

			var animation = new CABasicAnimation();
			animation.KeyPath = @"transform.rotation";
			animation.Duration = 4f;
			animation.From = NSNumber.FromInt32(0);
			animation.To = NSNumber.FromDouble(2 * Math.PI);
			animation.RepeatCount = float.MaxValue;
			_progressLayer.AddAnimation(animation, kMMRingRotationAnimationKey);

			var headAnimation = new CABasicAnimation();
			headAnimation.KeyPath = @"strokeStart";
			headAnimation.Duration = 1;
			headAnimation.From = NSNumber.FromInt32(0);
			headAnimation.To = NSNumber.FromFloat(0.25f);
			headAnimation.TimingFunction = TimingFunction;

			var tailAnimation = new CABasicAnimation();
			tailAnimation.KeyPath = @"strokeEnd";
			tailAnimation.Duration = 1;
			tailAnimation.From = NSNumber.FromInt32(0);
			tailAnimation.To = NSNumber.FromInt32(1);
			tailAnimation.TimingFunction = TimingFunction;

			var endHeadAnimation = new CABasicAnimation();
			endHeadAnimation.KeyPath = @"strokeStart";
			endHeadAnimation.BeginTime = 1;
			endHeadAnimation.Duration = 0.5f;
			endHeadAnimation.From = NSNumber.FromFloat(0.25f);
			endHeadAnimation.To = NSNumber.FromFloat(1f);
			endHeadAnimation.TimingFunction = TimingFunction;

			var endTailAnimation = new CABasicAnimation();
			endTailAnimation.KeyPath = @"strokeEnd";
			endTailAnimation.BeginTime = 1.0f;
			endTailAnimation.Duration = 0.5f;
			endTailAnimation.From = NSNumber.FromFloat(1f);
			endTailAnimation.To = NSNumber.FromFloat(1f);
			endTailAnimation.TimingFunction = TimingFunction;

			var animations = new CAAnimationGroup();
			animations.Duration = 1.5f;
			animations.Animations = new[] { headAnimation, tailAnimation, endHeadAnimation, endTailAnimation };
			animations.RepeatCount = float.MaxValue;
			_progressLayer.AddAnimation(animations, kMMRingStrokeAnimationKey);

			IsAnimating = true;
			if (HidesWhenStopped)
			{
				Hidden = false;
			}
		}

		public void StopAnimating()
		{
			if (!IsAnimating)
				return;
			_progressLayer.RemoveAnimation(kMMRingRotationAnimationKey);
			_progressLayer.RemoveAnimation(kMMRingStrokeAnimationKey);
			IsAnimating = false;
			if (HidesWhenStopped)
			{
				Hidden = true;
			}
		}

		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);
			NSNotificationCenter.DefaultCenter.RemoveObserver(this, UIApplication.DidBecomeActiveNotification);
		}

		public override void LayoutSubviews()
		{
			base.LayoutSubviews();

			_progressLayer.Frame = new CGRect(0, 0, Bounds.Width, Bounds.Height);
			this.UpdatePath();
		}

		public override void TintColorDidChange()
		{
			base.TintColorDidChange();
			_progressLayer.StrokeColor = TintColor.CGColor;
		}

		private void Initilize()
		{
			TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut);

			_progressLayer = CreateLayer();
			Layer.AddSublayer(_progressLayer);

			NSNotificationCenter.DefaultCenter.AddObserver(this, new Selector("resetAnimations"), UIApplication.DidBecomeActiveNotification, null);
		}

		[Export("resetAnimations")]
		private void ResetAnimations()
		{
			if (IsAnimating)
			{
				StopAnimating();
				StartAnimating();
			}
		}

		private void UpdatePath()
		{
			var center = new CGPoint(Bounds.GetMidX(), Bounds.GetMidY());
			var radius = NMath.Min(Bounds.Width / 2f, Bounds.Height / 2f - _progressLayer.LineWidth / 2f);
			nfloat startAngle = 0;
			var endAngle = 2 * NMath.PI;

			var path = UIBezierPath.FromArc(center, radius, startAngle, endAngle, true);
		 
			_progressLayer.Path = path.CGPath;
			_progressLayer.StrokeStart = 0;
			_progressLayer.StrokeEnd = 0;
			_progressLayer.LineCap = CAShapeLayer.CapRound;
		}

		private CAShapeLayer CreateLayer()
		{
			var r = new CAShapeLayer();
			r.StrokeColor = TintColor.CGColor;
			r.FillColor = null;
			r.LineWidth = 2f;
			return r;
		}
		#endregion

	}
}

